﻿using NDF;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace System.Web.Mvc
{
    /// <summary>
    /// 表示一个特性，该特性用于调用方对操作方法的访问。
    /// 在 NetDirkFramework 应用程序中，所有的授权验证服务请勿直接继承于特性类 <see cref="System.Web.Mvc.AuthorizeAttribute"/>，而应该继承于该特性类。
    /// 在该特性类的子类中，请勿直接重写 AuthorizeCore、OnAuthorization、OnCacheAuthorization、HandleUnauthorizedRequest 以实现相应的验证或缓存效果，而应该重写其对应的
    /// NDFAuthorizeCore、OnNDFAuthorization、OnNDFCacheAuthorization、NDFHandleUnauthorizedRequest 方法以达到同样效果，否则某些特定的过滤验证效果将不能够实现。
    /// </summary>
    public class NDFAuthorizeAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// 提供一个入口点用于进行自定义授权检查。
        /// 注意：在特性类 <see cref="NDFAuthorizeAttribute"/> 的子类中，请勿直接重写该方法，而应该重写其对应的 <seealso cref="NDFAuthorizeCore"/> 方法以达到同样效果，否则某些特定的过滤验证效果将不能够实现。
        /// </summary>
        /// <param name="httpContext">HTTP 上下文，它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。</param>
        /// <returns>如果用户已经过授权，则为 true；否则为 false。</returns>
        protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
        {
            return this.NDFAuthorizeCore(httpContext);
        }

        /// <summary>
        /// 在过程请求授权时调用。
        /// 注意：在特性类 <see cref="NDFAuthorizeAttribute"/> 的子类中，请勿直接重写该方法，而应该重写其对应的 <seealso cref="OnNDFAuthorization"/> 方法以达到同样效果，否则某些特定的过滤验证效果将不能够实现。
        /// </summary>
        /// <param name="filterContext">筛选器上下文，它封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。</param>
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            this.OnNDFAuthorization(filterContext);
        }

        /// <summary>
        /// 在缓存模块请求授权时调用。
        /// 注意：在特性类 <see cref="NDFAuthorizeAttribute"/> 的子类中，请勿直接重写该方法，而应该重写其对应的 <seealso cref="OnNDFCacheAuthorization"/> 方法以达到同样效果，否则某些特定的过滤验证效果将不能够实现。
        /// </summary>
        /// <param name="httpContext">HTTP 上下文，它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。</param>
        /// <returns>对验证状态的引用。</returns>
        protected override HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
        {
            return this.OnNDFCacheAuthorization(httpContext);
        }

        /// <summary>
        /// 处理未能授权的 HTTP 请求。
        /// 注意：在特性类 <see cref="NDFAuthorizeAttribute"/> 的子类中，请勿直接重写该方法，而应该重写其对应的 <seealso cref="NDFHandleUnauthorizedRequest"/> 方法以达到同样效果，否则某些特定的过滤验证效果将不能够实现。
        /// </summary>
        /// <param name="filterContext">封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。</param>
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            this.NDFHandleUnauthorizedRequest(filterContext);
        }




        /// <summary>
        /// 重写时，提供一个入口点用于进行自定义授权检查。
        /// 注意：在特性类 <see cref="NDFAuthorizeAttribute"/> 的子类中，请通过重写此方法而不是 <seealso cref="AuthorizeCore"/> 来达到授权验证的相应效果，否则某些特定的过滤验证效果将不能够实现。
        /// </summary>
        /// <param name="httpContext">HTTP 上下文，它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。</param>
        /// <returns>如果用户已经过授权，则为 true；否则为 false。</returns>
        protected virtual bool NDFAuthorizeCore(HttpContextBase httpContext)
        {
            return base.AuthorizeCore(httpContext);
        }

        /// <summary>
        /// 重写时，在过程请求授权时调用。
        /// 注意：不建议在特性类 <see cref="NDFAuthorizeAttribute"/> 的子类中重写该方法来达到授权验证的相应效果。
        /// 而是建议通过重写
        ///     NDFAuthorizeCore(用于判断是否为经过验证的用户请求)、
        ///     NDFIgnoreAuthorize(用于处理是否让当前请求绕过验证)、
        ///     NDFHandleIgnoreAuthorize(用于处理在当前请求绕过验证时的请求授权)、
        ///     OnNDFCacheAuthorization(用于处理缓存模块请求授权)、
        ///     NDFHandleAllowedRequest(用于处理经过授权的 HTTP 请求) 或
        ///     NDFHandleUnauthorizedRequest(用于处理未经授权的 HTTP 请求) 来以达到同样效果。
        /// </summary>
        /// <param name="filterContext">筛选器上下文，它封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。</param>
        public virtual void OnNDFAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
            {
                throw new InvalidOperationException("MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache");
            }

            Type allowAnonymousAttribute = typeof(AllowAnonymousAttribute);
            bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(allowAnonymousAttribute, inherit: true)
                    || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(allowAnonymousAttribute, inherit: true);
            if (skipAuthorization)
            {
                return;
            }

            Type allowAuthorizeAttribute = typeof(AllowAuthorizeAttribute);
            bool skipAllowAuthorize = filterContext.ActionDescriptor.GetCustomAttributes(allowAuthorizeAttribute, true).OfType<AllowAuthorizeAttribute>().Any(AllowAuthorizeValidateHandler)
                    || filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(allowAuthorizeAttribute, true).OfType<AllowAuthorizeAttribute>().Any(AllowAuthorizeValidateHandler);
            if (skipAllowAuthorize)
            {
                return;
            }

            if (this.NDFIgnoreAuthorize(filterContext))
            {
                this.NDFHandleIgnoreAuthorize(filterContext);
                return;
            }

            if (this.AuthorizeCore(filterContext.HttpContext))
            {
                HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
                cachePolicy.SetProxyMaxAge(new TimeSpan(0));
                cachePolicy.AddValidationCallback(this.CacheValidateHandler, null /* data */);
                this.NDFHandleAllowedRequest(filterContext);
            }
            else
            {
                this.HandleUnauthorizedRequest(filterContext);
            }
        }

        /// <summary>
        /// 重写时，在缓存模块请求授权时调用。
        /// 注意：在特性类 <see cref="NDFAuthorizeAttribute"/> 的子类中，请通过重写此方法而不是 <seealso cref="OnCacheAuthorization"/> 来达到授权验证的相应效果，否则某些特定的过滤验证效果将不能够实现。
        /// </summary>
        /// <param name="httpContext">HTTP 上下文，它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。</param>
        /// <returns>对验证状态的引用。</returns>
        protected virtual HttpValidationStatus OnNDFCacheAuthorization(HttpContextBase httpContext)
        {
            return base.OnCacheAuthorization(httpContext);
        }

        /// <summary>
        /// 重写时，处理是否让当前请求绕过 <seealso cref="NDFAuthorizeCore"/> 的授权验证。
        /// </summary>
        /// <param name="filterContext">封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。</param>
        /// <returns>如果让当前请求可以绕过 <seealso cref="NDFAuthorizeCore"/> 的授权验证，则为 true；否则为 false。</returns>
        protected virtual bool NDFIgnoreAuthorize(AuthorizationContext filterContext)
        {
            return false;
        }

        /// <summary>
        /// 重写时，处理在当前请求绕过验证时的请求授权。
        /// </summary>
        /// <param name="filterContext">封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。</param>
        protected virtual void NDFHandleIgnoreAuthorize(AuthorizationContext filterContext)
        {
        }

        /// <summary>
        /// 重写时，处理经过授权的 HTTP 请求。
        /// </summary>
        /// <param name="filterContext">封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。</param>
        protected virtual void NDFHandleAllowedRequest(AuthorizationContext filterContext)
        {
        }

        /// <summary>
        /// 重写时，处理未能授权的 HTTP 请求。
        /// 注意：在特性类 <see cref="NDFAuthorizeAttribute"/> 的子类中，请通过重写此方法而不是 <seealso cref="HandleUnauthorizedRequest"/> 来达到授权验证的相应效果，否则某些特定的过滤验证效果将不能够实现。
        /// </summary>
        /// <param name="filterContext">封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。</param>
        protected virtual void NDFHandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            base.HandleUnauthorizedRequest(filterContext);
        }



        private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
        {
            validationStatus = this.OnCacheAuthorization(new HttpContextWrapper(context));
        }

        private bool AllowAuthorizeValidateHandler(AllowAuthorizeAttribute attribute)
        {
            if (attribute.AllowType == null)
            {
                return true;
            }
            Type thisType = this.GetType();
            return thisType == attribute.AllowType || (attribute.AllowInherited && attribute.AllowType.IsAssignableFrom(thisType));
        }
    }
}
